package com.tju.ocean_ecology_website.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tju.ocean_ecology_website.dto.ApiResponse;
import com.tju.ocean_ecology_website.service.TokenBlacklistService;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * JWT请求过滤器，用于验证JWT令牌
 */
@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired(required = false)
    private TokenBlacklistService tokenBlacklistService;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        final String requestTokenHeader = request.getHeader("Authorization");

        // 如果请求路径是公开的，直接放行
        String requestPath = request.getRequestURI();
        if (requestPath.startsWith("/api/auth/") || requestPath.startsWith("/api/public/") || requestPath.startsWith("/uploads/")) {
            chain.doFilter(request, response);
            return;
        }

        String username = null;
        String jwtToken = null;

        // JWT Token格式为 "Bearer token"，移除Bearer前缀
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);

            // 检查令牌是否在黑名单中
            if (tokenBlacklistService != null && tokenBlacklistService.isBlacklisted(jwtToken)) {
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "令牌已失效，请重新登录");
                return;
            }

            try {
                username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            } catch (ExpiredJwtException e) {
                logger.warn("JWT Token has expired", e);
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "令牌已过期，请重新登录");
                return;
            } catch (JwtException e) {
                logger.warn("Invalid JWT Token", e);
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "无效的令牌");
                return;
            } catch (IllegalArgumentException e) {
                logger.warn("Unable to get JWT Token", e);
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "无法获取令牌");
                return;
            }
        } else if (requestTokenHeader == null) {
            logger.warn("JWT Token is missing");
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "缺少认证令牌");
            return;
        } else {
            logger.warn("JWT Token does not begin with Bearer String");
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "令牌格式错误");
            return;
        }

        // 验证令牌
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            try {
                UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);

                // 如果令牌有效，则配置Spring Security使用该令牌
                if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    // 设置认证信息
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);

                    // 继续过滤器链
                    chain.doFilter(request, response);
                } else {
                    sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "令牌验证失败");
                }
            } catch (UsernameNotFoundException e) {
                logger.error("User not found with username: " + username, e);
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "用户不存在");
            }
        } else {
            // 如果没有认证信息，继续过滤器链
            chain.doFilter(request, response);
        }
    }

    /**
     * 发送错误响应
     */
    private void sendErrorResponse(HttpServletResponse response, int statusCode, String message) throws IOException {
        response.setStatus(statusCode);
        response.setContentType("application/json;charset=UTF-8");

        ApiResponse<Object> errorResponse = ApiResponse.error(statusCode, message);
        response.getWriter().write(objectMapper.writeValueAsString(errorResponse));
    }
}
